import json
import os

import openpyxl
from openpyxl.styles import Alignment

from C99.Lexer import TokenType, Lexer


class Extractor:
    def __init__(self, lexer):
        self.lexer = lexer

    def skipFunction(self):
        pass

    def extractDefine(self):
        startP = self.lexer.peekToken().startPos
        self.lexer.getNextToken()
        self.lexer.getNextToken()
        cnt = 1
        while not self.lexer.isNewLine():
            token = self.lexer.getNextToken()
            cnt += 1
        endP = self.lexer.getNextToken().startPos
        # print(self.lexer.content[startP: endP-1])
        return (cnt>2, self.lexer.content[startP: endP-1])

    def extractTypeDefAndStructAndEnumAndUnion(self, prefix):
        lBrace = 0
        lParen = 0
        startP = self.lexer.peekToken().startPos
        firstLBrace = False
        isFunction = False
        valid = True
        self.lexer.getNextToken()
        token = self.lexer.peekToken()
        while not token.isEnd():
            if token.tokenType==TokenType.LBRACE:
                firstLBrace = True
                lBrace += 1
            elif token.tokenType==TokenType.RBRACE:
                lBrace -= 1
            else:
                pass
            if token.tokenType==TokenType.LPAREN:
                lParen += 1
            elif token.tokenType==TokenType.RPAREN:
                lParen -= 1
            else:
                pass
            # 判断是不是函数
            if token.tokenType==TokenType.LPAREN and not firstLBrace:
                isFunction = True
                valid = False
            # 函数的结束规则
            if isFunction:
                # 有函数体，花括号为准
                if firstLBrace:
                    if lBrace==0:
                        break
                else: # 无函数体， ;作为结束
                    if lParen==0 and self.lexer.peekToken().tokenType==TokenType.SEMICOLON:
                        break
            else:
                # 声明的结束
                if token.tokenType==TokenType.SEMICOLON and lBrace==0:
                    break
                # 函数参数里面的
                if token.tokenType==TokenType.RPAREN and not firstLBrace:
                    lParen += 1
                    isFunction = True
                    valid = False
            self.lexer.getNextToken()
            token = self.lexer.peekToken()
        endP = self.lexer.getNextToken().endPos+1
        # print(self.lexer.content[startP: endP])
        if valid and prefix.lower()!='typedef':
            valid = "{" in self.lexer.content[startP: endP]
        return (valid, self.lexer.content[startP: endP])

    def extract(self):
        token = self.lexer.peekToken()
        result = {
            "define": [],
            "typedef": [],
            "enum": [],
            "struct": [],
            "union": []
        }
        while not token.isEnd():
            if token.tokenType == TokenType.PREPROCESSOR and self.lexer.peekToken(2).content.lower()=='define':
                valid, content = self.extractDefine()
                if valid:
                    result["define"].append(content)
            elif token.content.lower() in ("struct", "typedef", "union", "enum"):
                prefix = token.content.lower()
                valid, content = self.extractTypeDefAndStructAndEnumAndUnion(token.content)
                if valid:
                    result[prefix].append(content)
            else:
                self.lexer.getNextToken()
            token = self.lexer.peekToken()
        return result


class Utils:
    @staticmethod
    def extractFile(path):
        print(path)
        with open(path, "r", encoding="UTF-8") as f:
            code = f.read()
        lexer = Lexer(code)
        extractor = Extractor(lexer)
        result = extractor.extract()
        print(json.dumps(result, indent=4, ensure_ascii=False))
        return result

    @staticmethod
    def extractFolder(folder):
        result = {
            "define": [],
            "typedef": [],
            "enum": [],
            "struct": [],
            "union": []
        }
        for root, _, files in os.walk(folder):
            for file in files:
                if file.endswith('.c') or file.endswith('.h'):
                    absPath = os.path.join(root, file)
                    # print(absPath)
                    r = Utils.extractFile(absPath)
                    for key, value in result.items():
                        value.extend(r[key])
        print(json.dumps(result, indent=4, ensure_ascii=False))
        # for key, value in result.items():
        #     print(key)
        #     for item in value:
        #         print(item)
        #     print("*********************")
        return result

    @staticmethod
    def save(path, result):
        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = " "
        rowIdx = 2
        cellTitleType = ws.cell(row=1, column=1, value="类型")
        cellTitleDefine = ws.cell(row=1, column=2, value="定义")

        cellTitleType.alignment = Alignment(
            vertical='center',  # 文本顶部对齐
            horizontal='center'  # 文本左对齐
        )
        cellTitleDefine.alignment = Alignment(
            vertical='center',  # 文本顶部对齐
            horizontal='center'  # 文本左对齐
        )

        for key, value in result.items():
            for item in value:
                ws.column_dimensions["A"].width = 40
                ws.column_dimensions["B"].width = 150

                cell1 = ws.cell(row=rowIdx, column=1, value=key)
                cell2 = ws.cell(row=rowIdx, column=2, value=item)

                cell1.alignment = Alignment(
                    vertical='center',  # 文本顶部对齐
                    horizontal='center'  # 文本左对齐
                )
                cell2.alignment = Alignment(
                    vertical='center',  # 文本顶部对齐
                    horizontal='center',  # 文本左对齐
                    wrapText=True
                )
                ws.row_dimensions[rowIdx].height = 300
                rowIdx += 1
        wb.save(path)


if __name__ == '__main__':
    pass